package plus.exp;

import java.util.List;

import plus.S_Function;
import plus.Type;
import plus.run.Emit;
import plus.run.VM;

public class E_Apply extends Exp {
	private Exp theThunk;
	private Exp[] es;
	private Type[] domain;

	public E_Apply(List<Exp> es) {
		this.theThunk = es.remove(0);
		this.es = new Exp[es.size()];
		int i = 0;
		for (Exp e:es) this.es[i++] = e;
	}
	@Override
	public void threadScope() {
		theThunk.threadScope();
		theThunk.checkThread();
		domain = new Type[es.length];
		int i = 0;
		for (Exp e:es) {
			e.threadScope();
			e.checkThread();
			domain[i++] = e.type;
		}
		S_Function s = new S_Function(domain);
		theThunk.type.unify_with(s);	// NOTE: A lambda is thus a callsite.
		type = s.range;
	}
	@Override String impliedName() { return es[0].impliedName(); }
	@Override String aThis() { return "the result of a lambda call"; }
	@Override
	public void compilePush() {
		S_Function sol = (S_Function)theThunk.type.getSolution();
		if (!sol.isVoid()) Emit.asm(VM.NUL); // Room for return value
		// Push from right to left.
		int i = es.length;
		while (i-->0) es[i].compilePush();
		// Go fetch the thunk.
		theThunk.compilePush();
		// Call it.
		Emit.callThunk();
	}
}
